﻿#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;
/// <summary>
/// AssetBundle资源包逻辑代码
/// </summary>
public partial class ESF_Logic
{
    /// <summary>
    /// 相对于日志目录的资源包目录
    /// </summary>
    readonly static string msrRelativeSaveLogDirectoryForAssetBundle = "AssetBundle";

    #region ClearAssetBunldeLog 清除AssetBundle日志
    /// <summary>
    /// 清除AssetBundle日志
    /// </summary>
    public static void ClearAssetBunldeLog()
    {
        ESF_Utility.ClearLogFolder(msrRelativeSaveLogDirectoryForAssetBundle);
    }
    #endregion

    #region WriteAssetBundleLog 写入AssetBundle日志
    /// <summary>
    /// 写入AssetBundle日志
    /// </summary>
    /// <param name="_asset">资源</param>
    /// <returns>保存文件地址</returns>
    public static string WriteAssetBundleLog(ESF_CollectAsset_AssetBundle _asset)
    {
        return _asset.SaveLog(msrRelativeSaveLogDirectoryForAssetBundle);
    }
    #endregion

    #region SetAllAssetBundleName 设置所有AssetBundle名称
    /// <summary>
    /// 设置所有AssetBundle名称
    /// </summary>
    /// <returns>true:成功,false:失败</returns>
    public static bool SetAllAssetBundleName()
    {
        bool result = true;
        float progress;
        Dictionary<string, ESF_CollectAsset_AssetBundle> topologyLink = OnCollectAssetDependencies();
        #region 设置AssetBundleName
        progress = 0;
        foreach (ESF_CollectAsset_AssetBundle n in topologyLink.Values)
        {
            progress++;
            n.SaveAssetBundleName();
            EditorUtility.DisplayProgressBar("Set AssetBundleName", n.path, progress / topologyLink.Count);
        }
        #endregion

        AssetDatabase.SaveAssets();
        AssetDatabase.RemoveUnusedAssetBundleNames();

        #region 节点日志
        progress = 0;
        ClearAssetBunldeLog();
        foreach (var key in topologyLink)
        {
            progress++;
            WriteAssetBundleLog(key.Value);
            EditorUtility.DisplayProgressBar("Save Log", key.Value.path, progress / topologyLink.Count);
        }
        ESF_P.ESF_Log("SetAllAssetBundleName success!");
        #endregion

        ESF_Utility.ExecuteMenuAssetsRefresh();
        EditorUtility.ClearProgressBar();
        return result;
    }
    #endregion

    #region  生成拓扑网络
    /// <summary>
    /// 生成拓扑网络
    /// </summary>
    /// <param name="topologyLink"></param>
    private static Dictionary<string, ESF_CollectAsset_AssetBundle> OnCollectAssetDependencies()
    {
        Dictionary<string, ESF_CollectAsset_AssetBundle> topologyLink = new Dictionary<string, ESF_CollectAsset_AssetBundle>();
        List<ESF_CollectAsset_AssetBundle> nodes = CollectAssetBundle<ESF_CollectAsset_AssetBundle>();
        Dictionary<string, ESF_CollectAsset_AssetBundle> rootNodes = new Dictionary<string, ESF_CollectAsset_AssetBundle>();
        float progress = 0;
        string error = string.Empty;

        languageSetting.xml.Resolve();
        #region 去掉不支持的语言目录
        List<string> unSupportFolders = new List<string>();
        foreach (var ab in assetBundleBuild.xml.unSupportLangs)
        {
            foreach (var f in ab.assetBundleFolders)
            {
                if (!unSupportFolders.Contains(f))
                {
                    unSupportFolders.Add(f);
                }
            }
        }

        List<ESF_CollectAsset_AssetBundle> unSupNodes = new List<ESF_CollectAsset_AssetBundle>();
        foreach (var key in nodes)
        {
            foreach (var f in unSupportFolders)
            {
                if (key.directory.StartsWith(f))
                {
                    unSupNodes.Add(key);
                    break;
                }
            }
        }

        foreach (var key in unSupNodes)
        {
            nodes.Remove(key);
        }
        #endregion

        #region 构建拓扑起始节点   
        foreach (var key in nodes)
        {
            if (key.IsAllowSetAssetBundle())
            {
                rootNodes.Add(key.path, key);
            }
            else
            {
                ESF_P.ESF_Error($"{key.path} is disallowed to set AssetBundleName");
            }
            progress++;
            EditorUtility.DisplayProgressBar("Build Topolopy Node", key.path, progress / nodes.Count);
        }
        #endregion

        #region 构建依赖链
        topologyLink = new Dictionary<string, ESF_CollectAsset_AssetBundle>();
        progress = 0;
        foreach (ESF_CollectAsset_AssetBundle n in nodes)
        {
            n.BuildDependency(topologyLink);
            progress++;
            EditorUtility.DisplayProgressBar("Collect Dependencies", n.path, progress / nodes.Count);
        }
        #endregion

        #region 收缩合并
        OnRecursiveShrinkMerge(topologyLink, rootNodes);
        progress = 0;
        List<string> removes = new List<string>();
        foreach (var key in topologyLink)
        {
            if (key.Value.isRootForuceShrinkMerge && !removes.Contains(key.Key))
            {
                removes.Add(key.Key);
            }
            progress++;
            EditorUtility.DisplayProgressBar("Collect ShrinkMerged Assets", key.Key, progress / topologyLink.Count);
        }
        EditorUtility.ClearProgressBar();
        progress = 0;
        foreach (var key in removes)
        {
            topologyLink.Remove(key);
            progress++;
            EditorUtility.DisplayProgressBar("Remove ShrinkMerged Asset", key, progress / removes.Count);
        }
        EditorUtility.ClearProgressBar();
        progress = 0;
        foreach (var key in topologyLink)
        {
            key.Value.FilterDependency(topologyLink);
            progress++;
            EditorUtility.DisplayProgressBar("Remove ShrinkMerged Asset", key.Key, progress / topologyLink.Count);
        }
        EditorUtility.ClearProgressBar();
        #endregion
        return topologyLink;
    }

    /// <summary>
    /// 递归收缩资源
    /// </summary>
    /// <param name="_topologyLink">拓扑资源</param>
    /// <param name="_rootNodes">根节点</param>
    private static void OnRecursiveShrinkMerge(Dictionary<string, ESF_CollectAsset_AssetBundle> _topologyLink,
        Dictionary<string, ESF_CollectAsset_AssetBundle> _rootNodes)
    {
        float progress = 0;
        List<ESF_CollectAsset_AssetBundle> nodes = new List<ESF_CollectAsset_AssetBundle>(_topologyLink.Values);
        List<string> checkedNodes = new List<string>();
        bool hasShrinkMerge = false;
        foreach (ESF_CollectAsset_AssetBundle n in nodes)
        {
            hasShrinkMerge |= n.ShrinkMerge(_topologyLink, _rootNodes, checkedNodes);
            progress++;
            EditorUtility.DisplayProgressBar("Collect Recursive Dependencies", n.path, progress / nodes.Count);
        }
        EditorUtility.ClearProgressBar();
        if (hasShrinkMerge)
        {
            OnRecursiveShrinkMerge(_topologyLink, _rootNodes);
        }
    }
    #endregion

    #region BuildSubPackage
    public static void BuildSubPackageToStreamingAsset() {

        ESF_P.ESF_Log("复制母包资源ToStreamingAssets");
        if (Directory.Exists(SFGlobalSetting.SubPacageStreamingAssetFilePath))
        {
            Directory.Delete(SFGlobalSetting.SubPacageStreamingAssetFilePath,true);
        }
        EditorUtility.ClearProgressBar();
        SubPackageInfo packageinfo = BuildSubPackage();
        SPI_ItemInfo[] baseItemInfo = packageinfo.SPI_BasePackage;
        string json = ESF_SubPackageManager.GetSubPackageJson(packageinfo);
        for (int i = 0; i < baseItemInfo.Length; i++)
        {
            SPI_ItemInfo baseItem = baseItemInfo[i];
            string tampPersistentPath = Path.Combine(SFGlobalSetting.assetBundleRoot, baseItem.AssetBundlPath);
            string tampSteamPath = Path.Combine(SFGlobalSetting.streamingAssetsRoot, baseItem.AssetBundlPath);
            FileInfo tampfile = new FileInfo(tampSteamPath);
            if (!Directory.Exists(tampfile.Directory.FullName))
            {
                Directory.CreateDirectory(tampfile.Directory.FullName);
            }
            FileInfo file = new FileInfo(tampPersistentPath);
            file.CopyTo(tampSteamPath);
            float slider = (float)(i) / baseItemInfo.Length;

            EditorUtility.DisplayProgressBar("正在复制", tampSteamPath, slider);
        }
        using (FileStream fs_sp = new FileStream(SFGlobalSetting.SubPacageStreamingAssetFilePath, FileMode.CreateNew))
        {
            using (StreamWriter sw_sp = new StreamWriter(fs_sp))
            {
                sw_sp.Write(json);
                sw_sp.Close();
            }
            fs_sp.Close();
        }
        string path = Path.Combine(SFGlobalSetting.assetBundleRoot, SFGlobalSetting.platform).Replace('\\', '/');
        string targetPath = Path.Combine(SFGlobalSetting.streamingAssetsRoot, SFGlobalSetting.platform).Replace('\\', '/');
        if (File.Exists(path))
        {
            FileInfo file = new FileInfo(path);
            file.CopyTo(targetPath);
        }
        EditorUtility.ClearProgressBar();
        AssetDatabase.Refresh();
    }
    public static SubPackageInfo BuildSubPackage()
    {

        SubPackageInfo packageInfo = null;
        AssetBundleManifest manifest = null;
        SFAssetUtility.LoadFile(SFGlobalSetting.platform, out byte[] data);
        AssetBundle ab = AssetBundle.LoadFromMemory(data);
        if (ab != null)
        {
            manifest = ab.LoadAsset<AssetBundleManifest>(SFGlobalSetting.manifestName);
            ab.Unload(false);
            ab = null;
        }
        int allassets = 0;
        if (manifest !=null)
        {
            Dictionary<string,List<string>> topologyLink = new Dictionary<string, List<string>>();

            Dictionary<string, int> dic = new Dictionary<string, int>();

            string[] allAsset = manifest.GetAllAssetBundles();
            for (int i = 0; i < allAsset.Length; i++)
            {
                dic[allAsset[i]] = 1;
                List<string> tampList = new List<string>();
                topologyLink[allAsset[i]] = tampList;
                string[] deps = manifest.GetAllDependencies(allAsset[i]);
                for (int j = 0; j < deps.Length; j++)
                {

                    dic[deps[j]] = 1;
                    tampList.Add(deps[j]);
                }
            }
            allassets = dic.Count;
            SPI_ItemInfo[] baseItemInfo;
            SPI_Language[] languages = Analysis_Language(topologyLink);
            SPI_Package[] packages = Analysis_SubPackage(topologyLink, out baseItemInfo);
            SPI_LoadingWindow[] downloadwindow = Analysis_FirstDownLoadWindow(topologyLink);
            packageInfo = new SubPackageInfo();
            packageInfo.SPI_Languages = languages;
            packageInfo.SPI_Packages = packages;
            packageInfo.SPI_BasePackage = baseItemInfo;
            packageInfo.SPI_DownLoadWindow = downloadwindow;
            string json = ESF_SubPackageManager.GetSubPackageJson(packageInfo);
            string savePath = SFGlobalSetting.SubPacagePersistentFilePath;
            File.WriteAllText(savePath, json);
            ESF_P.ESF_Log("生成分包信息成功");
          
        }
       
        return packageInfo;
    }

    #region 语言包

    /// <summary>
    ///  语言包
    /// </summary>
    /// <param name="topologyLink"></param>
    /// <returns></returns>
    private static SPI_Language[] Analysis_Language(Dictionary<string, List<string>> topologyLink)
    {
        List<SPI_Language> m_language = new List<SPI_Language>();
        Dictionary<string, List<string>> Dic_Clone = topologyLink;
        Dictionary<int, Dictionary<string, List<string>>> Dic_Language = new Dictionary<int, Dictionary<string, List<string>>>();
        //整理1：Dic_Clone 去除CN以外的头文件 2. Dic_Language ： Key：语言包 《Key:主文件 ，Value：依赖资源文件》
        for (int i = 0; i < assetBundleBuild.xml.supportLangs.Length; i++)
        {
            ESF_Xml_BuildAssetBundle_Lang eSF_Xml_BuildAssetBundle_Lang = assetBundleBuild.xml.supportLangs[i];
            if (eSF_Xml_BuildAssetBundle_Lang.classify!= enESF_AllLanguageClassify.CN)
            {
                Dictionary<string, List<string>> m_TampLanguage = new Dictionary<string, List<string>>();
                int index = (int)eSF_Xml_BuildAssetBundle_Lang.classify;
                foreach (var item in Dic_Clone)
                {
                    for (int j = 0; j < eSF_Xml_BuildAssetBundle_Lang.assetBundleFolders.Length; j++)
                    {
                        string path = eSF_Xml_BuildAssetBundle_Lang.assetBundleFolders[j].ToLower();

                        if (item.Key.Contains(path))
                        {
                            m_TampLanguage[item.Key] = item.Value;
                            
                            break;
                        }
                    }
                }
                foreach (var item in m_TampLanguage)
                {
                    Dic_Clone.Remove(item.Key);
                }
                Dic_Language[index] = m_TampLanguage;
            }
        }

        // 开始展开Dic_Clone 
        Dictionary<string, SPI_ItemInfo> Dic_AllAsset = new Dictionary<string, SPI_ItemInfo>();
        foreach (var item in Dic_Clone)
        {
            OnSaveItem(Dic_AllAsset,item.Key);
            for (int i = 0; i < item.Value.Count; i++)
            {
                OnSaveItem(Dic_AllAsset, item.Value[i]);
            }
        }

        foreach (var item in Dic_Language)
        {
            SPI_Language sPI_Language = new SPI_Language();
            sPI_Language.Language = item.Key - 1;
            List<SPI_ItemInfo> infos = new List<SPI_ItemInfo>();
            List<string> md5 = new List<string>();
            foreach (var package in item.Value)
            {
                SPI_ItemInfo info = OnGetItemInfo(package.Key);
                if (!md5.Contains(info.MD5))
                {
                    infos.Add(info);
                    md5.Add(info.MD5);
                }
                for (int i = 0; i < package.Value.Count; i++)
                {
                    string m_Path = package.Value[i];
                    SPI_ItemInfo tampinfo = OnGetItemInfo(package.Key);
                    if (!Dic_AllAsset.ContainsKey(tampinfo.MD5))
                    {
                        if (!md5.Contains(tampinfo.MD5))
                        {
                            infos.Add(tampinfo);
                            md5.Add(tampinfo.MD5);
                        }
                    }
                }
            }
            sPI_Language.LanguageInfos = infos.ToArray();
            m_language.Add(sPI_Language);
        }
        return m_language.ToArray();
    }

    private static SPI_ItemInfo OnGetItemInfo(string assetpath) {
        string path = OnGetRootPath(assetpath);
        string fileMd5 = SFAssetUtility.GetMD5HashFromFile(path);
        FileInfo fInfo = new FileInfo(path);
        SPI_ItemInfo info = new SPI_ItemInfo();

        info.AssetBundlPath = assetpath.ESF_TransPathSeparatorCharToUnityChar();
        info.MD5 = fileMd5;
        info.Size = (int)fInfo.Length;
        return info;
    }

    private static void OnSaveItem(Dictionary<string, SPI_ItemInfo> Dic_ItemInfo,string assetpath)
    {
        string path = OnGetRootPath(assetpath);
        string fileMd5 = SFAssetUtility.GetMD5HashFromFile(path);
        FileInfo fInfo = new FileInfo(path);
        SPI_ItemInfo info = new SPI_ItemInfo();

        info.AssetBundlPath = assetpath.ESF_TransPathSeparatorCharToUnityChar();
        info.MD5 = fileMd5;
        info.Size = (int)fInfo.Length;
        Dic_ItemInfo[fileMd5] = info;
    }

    private static string OnGetRootPath(string path)
    {
        string fullpath = string.Empty;
        fullpath = Path.Combine(SFGlobalSetting.assetBundleRoot, path).ESF_TransPathSeparatorCharToUnityChar();
        return fullpath;
    }
    #endregion

    #region 分包

    private static SPI_Package[] Analysis_SubPackage(Dictionary<string, List<string>> topologyLink,out SPI_ItemInfo[] baseItemInfo) {
        baseItemInfo = null;
        Dictionary<string, MainifestInfo> m_DicAllMainfest =  OnUnfoldMainifest(topologyLink);
        Dictionary<string, SubChildPackageInfo> m_DicSubPack = OnUnfoldSubPackage(topologyLink);
        EliminateAssets(m_DicAllMainfest, m_DicSubPack);
        Dictionary<int,SPI_Package> page = new Dictionary<int, SPI_Package>();
        foreach (var item in m_DicSubPack)
        {
            for (int i = 0; i < item.Value.SubPackageIndex.Count; i++)
            {
                int index = item.Value.SubPackageIndex[i] + 1;
                SPI_Package subpage;
                if (!page.TryGetValue(index,out subpage))
                {
                    subpage = new SPI_Package();
                    page[index] = subpage;
                    subpage.SubPageIndex = index;
                }
                List<SPI_ItemInfo> subtampitem = new List<SPI_ItemInfo>();
                if (subpage.SubPageItems!=null)
                {
                    subtampitem.AddRange(subpage.SubPageItems);
                }
                subtampitem.Add(item.Value.Self);
                subpage.SubPageItems = subtampitem.ToArray();
            }
        }
        List<SPI_ItemInfo> baseitem = new List<SPI_ItemInfo>();
        foreach (var item in m_DicAllMainfest)
        {
            baseitem.Add(item.Value.Self);
            foreach (var child in item.Value.OnlyChild)
            {
                baseitem.Add(child.Value);
            }
        }
        baseItemInfo = baseitem.ToArray();
        return page.Values.ToArray();
    }
    private static bool CheckOneSelf(string assetmd5,out List<string> parentmd5, Dictionary<string, MainifestInfo> main, Dictionary<string, SubChildPackageInfo> subpack) {
        MainifestInfo info;
        bool isOnly = false;
        parentmd5 = new List<string>();
        if (main.TryGetValue(assetmd5,out info))
        {
            if (info.Parent.Count>0)
            {
                List<string> tampmd5 = new List<string>();
                foreach (var item in info.Parent)
                {
                    if (!subpack.ContainsKey(item.Key))
                    {
                        tampmd5.Add(item.Key);
                    }
                }
                if (tampmd5.Count == 1)
                {
                    List<string> root ;
                    if (CheckOneSelf(tampmd5[0], out root, main, subpack))
                    {
                        parentmd5.AddRange(root);
                        isOnly=true;
                    }
                }
                else {
                    isOnly = false;
                }
               
            }
            else
            {
                parentmd5.Add(assetmd5);
                isOnly = true;
            }
        }
        return isOnly;
    }

    /// <summary>
    /// 剔除 主文件内容
    /// </summary>
    /// <param name="main"></param>
    /// <param name="subpack"></param>
    private static void EliminateAssets(Dictionary<string, MainifestInfo> main, Dictionary<string, SubChildPackageInfo> subpack) {
        List<string> md5_SubpackItemInBasePack = new List<string>();
        Dictionary<int, SPI_ItemInfo> m_DicAdd_subpack = new Dictionary<int, SPI_ItemInfo>();
        Dictionary<int,List<string>> saveSubPack = new Dictionary<int, List<string>>();
        List<string> removeSubPack = new List<string>();
        foreach (var item in subpack)
        {
            List<string> savesubpackMd5;
            if (CheckOneSelf(item.Key,out savesubpackMd5, main, subpack))
            {
                for (int i = 0; i < item.Value.SubPackageIndex.Count; i++)
                {
                    int index = item.Value.SubPackageIndex[i];
                    List<string> tamp;
                    if (!saveSubPack.TryGetValue(index,out tamp))
                    {
                        tamp = new List<string>();
                        saveSubPack[index] = tamp;
                    }
                    tamp.AddRange(savesubpackMd5);
                }
                
            }
            else
            {
                removeSubPack.Add(item.Key);
            }
        }
        foreach (var item in saveSubPack)
        {
            for (int i = 0; i < item.Value.Count; i++)
            {
                string md5 = item.Value[i];
                MainifestInfo info;
                if (main.TryGetValue(md5, out info))
                {
                    SubChildPackageInfo subchild = OnGetSubPackageInfo(info.Self.AssetBundlPath, subpack);
                    if (!subchild.SubPackageIndex.Contains(item.Key))
                    {
                        subchild.SubPackageIndex.Add(item.Key);
                    }
                }
            }
        }

        for (int i = 0; i < removeSubPack.Count; i++)
        {
            subpack.Remove(removeSubPack[i]);
        }

        foreach (var item in subpack)
        {
            main.Remove(item.Key);
        }
    }

    /// <summary>
    /// 解压子包
    /// </summary>
    /// <returns></returns>
    private static Dictionary<string, SubChildPackageInfo> OnUnfoldSubPackage(Dictionary<string, List<string>> topologyLink) {
        Dictionary<string, SubChildPackageInfo> subPackage = new Dictionary<string, SubChildPackageInfo>();
        for (int i = 0; i < assetBundleBuild.xml.SubPackageRoots.Length; i++)
        {
            int index = i ;
            string rootpath = assetBundleBuild.xml.SubPackageRoots[i].ESF_TransPathSeparatorCharToUnityChar().ToLower();
            foreach (var item in topologyLink)
            {
                if (item.Key.Contains(rootpath))
                {
                    SubChildPackageInfo tampsub = OnGetSubPackageInfo(item.Key, subPackage);
                    if (!tampsub.SubPackageIndex.Contains(index))
                    {
                        tampsub.SubPackageIndex.Add(index);
                    }
                    for (int j = 0; j < item.Value.Count; j++)
                    {
                        tampsub = OnGetSubPackageInfo(item.Value[j], subPackage);
                        if (!tampsub.SubPackageIndex.Contains(index))
                        {
                            tampsub.SubPackageIndex.Add(index);
                        }
                    }
                }
            }
        }
        return subPackage;
    }

    private static SubChildPackageInfo OnGetSubPackageInfo(string path,Dictionary<string, SubChildPackageInfo> dicsub) {
        SPI_ItemInfo subitem = OnGetItemInfo(path);
        SubChildPackageInfo packageInfo; 
        if (!dicsub.TryGetValue(subitem.MD5,out packageInfo))
        {
            packageInfo = new SubChildPackageInfo();
            packageInfo.Self = subitem;
            packageInfo.SubPackageIndex = new List<int>();
            dicsub[subitem.MD5] = packageInfo;
        }
        return packageInfo;
    }
    private static Dictionary<string, MainifestInfo> OnUnfoldMainifest (Dictionary<string, List<string>> topologyLink) {
        Dictionary<string, MainifestInfo> m_DicAllMainfest = new Dictionary<string, MainifestInfo>();
        foreach (var item in topologyLink)
        {
            /*
             * 处理Key
             */
            MainifestInfo mianKey;
            mianKey = OnGetMainifestInfo(m_DicAllMainfest, item.Key);
            /*
             * 处理Value
             */
            for (int i = 0; i < item.Value.Count; i++)
            {
                MainifestInfo depinfo;
                depinfo = OnGetMainifestInfo(m_DicAllMainfest, item.Value[i]);
                depinfo.Parent[mianKey.Self.MD5] = mianKey.Self;
            }
        }
       
        return m_DicAllMainfest;
    }

    /// <summary>
    /// 获取字典中已经存储的数据
    /// </summary>
    /// <param name="m_DicAllMainfest"></param>
    /// <param name="asstepath"></param>
    /// <returns></returns>
    private static MainifestInfo OnGetMainifestInfo(Dictionary<string, MainifestInfo> m_DicAllMainfest,string asstepath)
    {
        SPI_ItemInfo mainItemInfo = OnGetItemInfo(asstepath);
        MainifestInfo tampMainifestInfo;
        if (!m_DicAllMainfest.TryGetValue(mainItemInfo.MD5, out tampMainifestInfo))
        {
            tampMainifestInfo = new MainifestInfo();
            tampMainifestInfo.Self = mainItemInfo;
            tampMainifestInfo.Parent = new Dictionary<string, SPI_ItemInfo>();
            tampMainifestInfo.OnlyChild = new Dictionary<string, SPI_ItemInfo>();
            m_DicAllMainfest[mainItemInfo.MD5] = tampMainifestInfo;
        }
        return tampMainifestInfo;
    }

    private class SubChildPackageInfo {
        /// <summary>
        /// 自身
        /// </summary>
        public SPI_ItemInfo Self;
        /// <summary>
        /// 属于第几个Packge
        /// </summary>
        public List<int> SubPackageIndex;
    }
    private class MainifestInfo {

        /// <summary>
        /// 自身
        /// </summary>
        public SPI_ItemInfo Self;
        /// <summary>
        /// 被依赖对象
        /// </summary>
        public Dictionary<string, SPI_ItemInfo>  Parent;

        /// <summary>
        /// 单线依赖
        /// </summary>
        public Dictionary<string, SPI_ItemInfo> OnlyChild;
    }

    private static string OnGetRealPath(string item)
    {
        FileInfo file = new FileInfo(OnGetRootPath(item));
        string fullpath = file.FullName.Substring(0, file.FullName.Length - file.Extension.Length);
        file = new FileInfo(fullpath);
        string[] exten = file.Extension.Split('_');
        string baspath = file.FullName.Substring(0, file.FullName.Length - file.Extension.Length);
        baspath += exten[0];
        return baspath;
    }

    #endregion

    #region 第一个资源加载界面

    static SPI_LoadingWindow[] Analysis_FirstDownLoadWindow(Dictionary<string, List<string>> topologyLink) {
        List<SPI_LoadingWindow> infos = new List<SPI_LoadingWindow>();
        foreach (var item in assetBundleBuild.xml.FirstDownloadingWindowPath)
        {
            ESF_Xml_DonwLoadWindow_Lang window = item;
            SPI_LoadingWindow loadingWindow = new SPI_LoadingWindow();
            loadingWindow.Language = ((int)window.classify)-1;
            List<SPI_ItemInfo> tampInfo = new List<SPI_ItemInfo>();
            
            for (int i = 0; i < window.assetBundleFolders.Length; i++)
            {
                foreach (var allAssets in topologyLink)
                {
                    for (int j = 0; j < window.assetBundleFolders.Length; j++)
                    {
                        string path = window.assetBundleFolders[j].ESF_TransPathSeparatorCharToUnityChar().ToLower();
                        if (allAssets.Key.Contains(path))
                        {
                            SPI_ItemInfo info = OnGetItemInfo(allAssets.Key);
                            tampInfo.Add(info);
                            foreach (var subitem in allAssets.Value)
                            {
                                info = OnGetItemInfo(subitem);
                                tampInfo.Add(info);
                            }
                        }
                    }
                }
            }
            loadingWindow.LoadingWindowInfos = tampInfo.ToArray();
            infos.Add(loadingWindow);
        }
        return infos.ToArray();
    }

    #endregion 

    #endregion

    #region ClearAllAssetBundleName 清除所有AssetBundle名称
    /// <summary>
    /// 清除所有AssetBundle名称
    /// </summary>
    /// <returns>true:成功,false:失败</returns>
    public static bool ClearAllAssetBundleName()
    {
        string[] names = AssetDatabase.GetAllAssetBundleNames();
        StringBuilder sbLog = new StringBuilder();
        if (names != null && names.Length > 0)
        {
            float progress = 0;
            for (int i = 0; i < names.Length; i++)
            {
                progress++;
                AssetDatabase.RemoveAssetBundleName(names[i], true);
                EditorUtility.DisplayProgressBar("Clear AssetBundleName", names[i], progress / names.Length);
            }
            AssetDatabase.RemoveUnusedAssetBundleNames();
            AssetDatabase.SaveAssets();
        }
        sbLog.AppendLine("ClearAllAssetBundleName Succeed!");
        ESF_P.ESF_Log(sbLog.ToString());
        ESF_Utility.ExecuteMenuAssetsRefresh();
        EditorUtility.ClearProgressBar();
        return true;
    }
    #endregion
}
#endif
